﻿//BestByVolumeQuotingStrategy.cs
//Copyright (c) 2013 StockSharp LLC, all rights reserved.
//This code module is part of StockSharp library.
//This code is licensed under the GNU GENERAL PUBLIC LICENSE Version 3.
//See the file License.txt for the license details.
//More info on: http://stocksharp.com

namespace StockSharp.Algo.Strategies
{
	using System;
	using System.Linq;

	using Ecng.Collections;
	using Ecng.ComponentModel;

	using StockSharp.BusinessEntities;
	using StockSharp.Logging;

	/// <summary>
	/// Котирование по принципу "Лучшая по объему". Для данного котирования указывается дельта объема <see cref="VolumeExchange"/>,
	/// который может стоять перед котируемой заявкой.
	/// </summary>
	public class BestByVolumeQuotingStrategy : QuotingStrategy
	{
		/// <summary>
		/// Создать <see cref="BestByVolumeQuotingStrategy"/>.
		/// </summary>
		/// <param name="quotingDirection">Направление котирования.</param>
		/// <param name="quotingVolume">Объем, который необходимо скотировать.</param>
		public BestByVolumeQuotingStrategy(OrderDirections quotingDirection, decimal quotingVolume)
			: base(quotingDirection, quotingVolume)
		{
			_volumeExchange = new StrategyParam<Unit>(this, "VolumeExchange", new Unit());
		}

		/// <summary>
		/// Создать <see cref="BestByVolumeQuotingStrategy"/>.
		/// </summary>
		/// <param name="order">Заявка, которую необходимо котировать.</param>
		/// <param name="volumeExchange">Дельта объема, который может стоять перед котируемой заявкой.</param>
		/// <returns>Стратегия.</returns>
		public BestByVolumeQuotingStrategy(Order order, Unit volumeExchange)
			: base(order)
		{
			_volumeExchange = new StrategyParam<Unit>(this, "VolumeExchange", volumeExchange);
		}

		private readonly StrategyParam<Unit> _volumeExchange;

		/// <summary>
		/// Дельта объема, который может стоять перед котируемой заявкой.
		/// </summary>
		public Unit VolumeExchange
		{
			get { return _volumeExchange.Value; }
			set { _volumeExchange.Value = value; }
		}

		/// <summary>
		/// Нужно ли котировать заявку.
		/// </summary>
		/// <param name="currentPrice">Текущая цена.</param>
		/// <param name="currentVolume">Текущий объем.</param>
		/// <param name="acceptablePriceRange">Приемлемый диапазон цены.</param>
		/// <param name="newVolume">Новый объем.</param>
		/// <returns>Цена, по которой будет выставлена заявка. Если возвращается 0, то заявка выставляться не будет.</returns>
		protected override decimal NeedQuoting(decimal currentPrice, decimal currentVolume, Range<decimal> acceptablePriceRange, decimal newVolume)
		{
			var quotes = FilteredQuotes;

			if (quotes.IsEmpty())
			{
				this.AddWarningLog("Отсутствует информация о стакане. Невозможно посчитать объём перед заявкой.");
				return 0;
			}

			var sign = QuotingDirection == OrderDirections.Buy ? 1 : -1;
			var volume = quotes.Where(q => q.Price * sign > currentPrice * sign).Sum(q => q.Volume);
			return volume > (decimal)(currentVolume + VolumeExchange) ? GetOrderPrice(acceptablePriceRange) : 0;
		}
	}
}